package com.yb.login.center.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONObject;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.yb.auth.core.bean.SysUser;
import com.yb.auth.core.constant.LoginConstant;
import com.yb.core.bean.Resp;
import com.yb.core.constant.HttpConstant;
import com.yb.core.constant.RedisConstant;
import com.yb.core.exception.YbBusinessException;
import com.yb.core.util.JwtTokenUtil;
import com.yb.core.util.RedisUtil;
import com.yb.core.util.VerifyCodeUtil;
import com.yb.login.center.domain.VerifyCode;
import com.yb.login.center.service.IUserService;
import com.yb.login.center.template.AbstractUserServiceTemplate;
import com.yb.login.center.vo.LoginImgVo;
import com.yb.login.center.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {
    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    JwtTokenUtil jwtTokenUtil;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    Map<String, AbstractUserServiceTemplate> map;

    @Autowired
    private DefaultKaptcha captchaProducer;

    @Autowired
    VerifyCode verifyCode;

    @Override
    public Resp login(LoginVo loginVo) {
      log.info("loginVo:{}",JSONObject.toJSONString(loginVo));
      LoginConstant.LoginType loginType = LoginConstant.LoginType.parse(loginVo.getType());
      log.info("loginType:{}",loginType);
      return map.get(loginType.getName()).login(loginVo);

    }

    @Override
    public Resp logout(String authentication) {
        log.info("authentication={}",authentication);
        if(!StringUtils.hasText(authentication)){
            return Resp.error();
        }

        String userStr = redisUtil.get(String.format(RedisConstant.AUTH_TOKEN_KEY, authentication));

        if(!StringUtils.hasText(userStr)){
            return Resp.error(HttpConstant.Response.TOKEN_ERROR);
        }

        SysUser sysUser = JSONObject.parseObject(userStr, SysUser.class);

        log.info("logout sysUser :{}",JSONObject.toJSONString(sysUser));

        redisUtil.delete(Arrays.asList(String.format(RedisConstant.AUTH_USER_KEY, sysUser.getUsername(), sysUser.getUserId()),String.format(RedisConstant.AUTH_TOKEN_KEY, authentication)));

        return Resp.ok();
    }

    @Override
    public Resp verifyCode(LoginVo loginVo, HttpServletResponse response) {
        String mobile = loginVo.getMobile();
        log.info("mobile={}",mobile);
        if(!StringUtils.hasText(mobile)){
            return Resp.error(HttpConstant.Response.MOBILE_ERROR);
        }

        String verifyCode = redisUtil.get(String.format(RedisConstant.MOBILE_VERIFY_CODE, mobile));

        if(StringUtils.hasText(verifyCode)){
            return Resp.error(HttpConstant.Response.MOBILE_RATE_ERROR);
        }

        log.info("");

        verifyCode= VerifyCodeUtil.generateNumCode(this.verifyCode.getMobile().getLength());

        log.info("verifyCode :{}",verifyCode);

        LoginVo respVo = new LoginVo();

        redisUtil.set(String.format(RedisConstant.MOBILE_VERIFY_CODE, mobile),verifyCode,this.verifyCode.getMobile().getTimeout(), TimeUnit.SECONDS);

        respVo.setVerifyCode(verifyCode);

        try {
            this.generateImage(response,verifyCode);
        } catch (IOException e) {
            throw new YbBusinessException(e);
        }

        return null;
    }

    @Override
    public Resp verifyImgCode(HttpServletRequest request, HttpServletResponse response) {

        String verifyCode = VerifyCodeUtil.generateNumCode(this.verifyCode.getImage().getLength());
        byte[] captchaOutputStream = null;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        String imgUUID = IdUtil.simpleUUID();
        try {
            redisUtil.set(String.format(RedisConstant.MOBILE_VERIFY_IMG_CODE, imgUUID),verifyCode,60,TimeUnit.SECONDS);
//            this.generateImage(response,verifyCode);
           
       
                //生产验证码字符串并保存到session中
            BufferedImage challenge = captchaProducer.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
            byte[] bytes = imgOutputStream.toByteArray();
            LoginImgVo loginImgVo = new LoginImgVo();
            loginImgVo.setImgUUID(imgUUID);
            loginImgVo.setImgBase64("data:image/jpg;base64,"+Base64.getEncoder().encodeToString(bytes));
            return Resp.ok().data(loginImgVo);
        } catch (IOException e) {
            throw new YbBusinessException(e);
        }
    }


    private void generateImage(HttpServletResponse response,String verifyCode) throws IOException {
        byte[] captchaOutputStream = null;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            BufferedImage challenge = captchaProducer.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        captchaOutputStream = imgOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaOutputStream);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
}
